
#include "stdafx.h"

#include <Runtime.Low/Pipeline/Pipeline.h>
#include <cstdio>

using namespace TTGLib::Pipeline;

typedef unsigned __int64 MyT;

#define KC 10

template <int n>
struct Keys {
	MyT v[n][2];
	char str[n][16];
	int order;
	int places[n];
	int count;
	explicit Keys(int aOrder):order(aOrder),count(0) {}
};

typedef Keys<KC> Key;

template <int n>
inline bool getKey(FILE *f, Keys<n> *&k, int order) {
	static char buf[10];
	int i;
	k = new Keys<n>(order);
	for (i = 0; i < n; ++i) {
		if (!fgets(&k->str[i][0], 16, f)) break;
		fgets(buf, 10, f);
		k->v[i][0] = k->v[i][1] = 0;
		for (int j = 0; j < 8; j++)
			k->v[i][0] |= (((MyT)k->str[i][j]) << ((7 - j) << 3));
		for (int j = 8; j < 15; j++)
			k->v[i][1] |= (((MyT)k->str[i][j]) << ((14 - j) << 3));
	}
	k->count = i;
	return k->count > 0;
}

class FileReader: public Node<FILE *, Key *> {
protected:
	virtual void process(FILE *f) {
		static int num = 0;
		int i;
		Key *k;
		for (i = 10; i > 0; i--)
			if (getKey(f, k, num++))
				sendNext(k);
			else
				break;
		if (!i)
			sendThis(f);
	}
	long getDifficulty(FILE *f) {
		return 1;
	}
};

typedef MyT MyT2[2];

MyT2 *keysData;
int keysCount;

inline int cmpFunc(MyT *a, MyT *b) {
	return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 
		a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0;
}

class Searcher: public Node<Key *, Key *> {
protected:
	virtual void process(Key *k) {
		for (int i = 0; i < k->count; i++) {
			int a = 0;
			int b = keysCount - 1;
			int cmpRes = 0;
			int curIdx;
			while (b > a) {
				curIdx = (a + b) / 2;
				cmpRes = cmpFunc(&k->v[i][0], &keysData[curIdx][0]);
				if (!cmpRes)
					break;
				if (cmpRes > 0)
					a = curIdx + 1;
				else
					b = curIdx;
			}
			k->places[i] = (b - a) ? curIdx : cmpFunc(&k->v[i][0], &keysData[a][0]) ? -1 : a;
		}
		sendNext(k);
	}
	long getDifficulty(Key *k) {
		return 3;
	}
};

FILE *fout;

class FileWriter: public Node<Key *, bool> {
	int nOrder;
	std::list<Key *>::iterator lit;
	int litValid;
public:
	FileWriter():Node("FileWriter", true) {}
protected:
	virtual void onBegin() {
		nOrder = 0;
		litValid = 0;
	}
	virtual void chooseTaskData(std::list<Key *> &dataset, std::vector<Key *> &chosen) {
		for (std::list<Key *>::iterator it = litValid?lit:dataset.begin(); it != dataset.end(); it++) {
			if ((*it)->order == nOrder) {
				litValid = 0;
				chosen.push_back(*it);
				dataset.erase(it);
				break;
			}
			lit = it;
			litValid = 1;
		}
	}
	virtual void process(Key *k) {
		for (int i = 0; i < k->count; i++)
			if (k->places[i] >= 0)
				fprintf(fout, "%s is found at index  %d\n", &k->str[i][0], k->places[i]);
			else
				fprintf(fout, "%s is NOT FOUND\n", &k->str[i][0]);
		nOrder++;
	}
	long getDifficulty(Key *k) {
		return 2;
	}
};

inline void readKey(FILE *f, MyT2 &res) {
	static char buf[10];
	static unsigned char str[16];
	if (!fgets((char *)str, 16, f))
		return;
	if (!fgets(buf, 10, f))
		return;
	res[0] = res[1] = 0;
	for (int j = 0; j < 8; j++)
		res[0] |= (((MyT)str[j]) << ((7 - j) << 3));
	for (int j = 8; j < 15; j++)
		res[1] |= (((MyT)str[j]) << ((14 - j) << 3));
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc < 4) return 1;
	FILE *fKeys, *fToFind;
	fKeys = fopen(argv[1], "r");
	fscanf(fKeys, "%d", &keysCount);
	char buf[4];
	fgets(buf, 4, fKeys);
	keysData = new MyT2[keysCount];
	for (long i = 0; i < keysCount; i++) {
		readKey(fKeys, keysData[i]);
	}
	fclose(fKeys);
	fToFind = fopen(argv[2], "r");
	fout = fopen(argv[3], "w");
	Pipeline<FILE *, bool> mainPipe(NodeWrapper<FILE *, Key *>(new FileReader()) + NodeWrapper<Key *, Key *>(new Searcher()) + NodeWrapper<Key *, bool>(new FileWriter()));
	double startTime = BaseServices::_Timer().getTimeD();
	mainPipe.start(fToFind);
	double resultTime = (BaseServices::_Timer().getTimeD() - startTime) / 1000.0;
	printf("TIME = %lf\n", resultTime);
	fclose(fToFind);
	fclose(fout);

	return 0;
}
